﻿/*
 * Created by SharpDevelop.
 * User: wwlng1
 * Date: 9/15/2014
 * Time: 04:00 PM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Google.Apis.Calendar.v3.Data;

namespace cogs.Services
{
	/// <summary>
	/// Description of Appointment.
	/// </summary>
	public class Appointment
	{
		
		private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
		
		private Regex emailPattern = new Regex("\\W|[^a-zA-Z0-9]");
		
		public DateTime Start;
		public DateTime End;
		public string Subject;
		public string Body;
		public string Location;
		
		public string Organizer;
		public string RequiredAttendees;
		public string OptionalAttendees;
		
		public bool ReminderSet;
		public int ReminderMinutesBeforeStart;
		
		
		public string GoogleId;
		public string OfficeId;
		
		public string GoogleETag;
		
		public bool AllDayEvent = false;
		
		public Appointment()
		{
		}
		
		/// <summary>
		/// Convert Outlook Calendar item to a common data structure 
		/// Reference: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook.appointmentitem_members.aspx
		/// </summary>
		/// <param name="a">AppointmentItem from Outlook</param>
		public Appointment(Microsoft.Office.Interop.Outlook.AppointmentItem a)
		{
			Start = a.Start;
			End = a.End;
			Subject = a.Subject;
			Body = a.Body;
			Location = a.Location;
			OfficeId = a.GlobalAppointmentID;
			AllDayEvent = a.AllDayEvent;
			
			Organizer = a.Organizer;
			RequiredAttendees = a.RequiredAttendees;
			OptionalAttendees = a.OptionalAttendees;
			
			ReminderSet = a.ReminderSet;
			ReminderMinutesBeforeStart = a.ReminderMinutesBeforeStart;
			
		}		
		
		/// <summary>
		/// Convert Google Calendar item to a common data structure 
		/// Reference: https://developers.google.com/resources/api-libraries/documentation/calendar/v3/csharp/latest/classGoogle_1_1Apis_1_1Calendar_1_1v3_1_1Data_1_1Event.html
		/// </summary>
		/// <param name="e">Event item from Google</param>
		public Appointment(Google.Apis.Calendar.v3.Data.Event e)
		{

			AllDayEvent = (e.Start.Date != null);

			Start = CastEventDateTimeToDateTime(e.Start);
			End = CastEventDateTimeToDateTime(e.End);
			Subject = e.Summary;
			Body = e.Description;
			Location = e.Location;

			GoogleId = e.Id;
			GoogleETag = e.ETag;
			
			if (e.ExtendedProperties != null) {
				OfficeId = e.ExtendedProperties.Private[GoogleCalendarService.ExtendedPropertyOfficeId];
			}
			
		}

		public Google.Apis.Calendar.v3.Data.Event ToGoogleCalendarEvent() {
			Event e = new Google.Apis.Calendar.v3.Data.Event();
			
			e.Start = new EventDateTime();
			e.End = new EventDateTime();
			
			if(this.AllDayEvent) {
				e.Start.Date = this.Start.ToString("yyyy-MM-dd");
				e.End.Date = this.End.ToString("yyyy-MM-dd");
			}
			else {
				e.Start.DateTime = this.Start;
				e.End.DateTime = this.End;
			}
			
			e.Summary = this.Subject;
			e.Location = this.Location;
			e.Description = this.Body;
			
			e.ExtendedProperties = new Event.ExtendedPropertiesData();
			e.ExtendedProperties.Private = new Dictionary<string, string>();
			e.ExtendedProperties.Private[GoogleCalendarService.ExtendedPropertyOfficeId]=this.OfficeId;
			
			
			if(this.ReminderSet) {
				e.Reminders = new Event.RemindersData();
				e.Reminders.UseDefault = false;
				
				var reminder = new EventReminder();
				reminder.Method="popup";
				reminder.Minutes = this.ReminderMinutesBeforeStart;
				
				e.Reminders.Overrides = new List<EventReminder>();
				e.Reminders.Overrides.Add(reminder);
			}
			
			
						
			if (this.Organizer!=null || this.RequiredAttendees!=null || this.OptionalAttendees!=null) {
				e.Attendees = new List<EventAttendee>();
				
				if(this.Organizer!=null) {
					EventAttendee attendee = new EventAttendee();
					attendee.Email=GenerateDummyEmail(this.Organizer);
					attendee.DisplayName = this.Organizer;
					attendee.Organizer = true;
					e.Attendees.Add(attendee);
				}
				
				if(this.RequiredAttendees!=null) {
					string[] attendees = this.RequiredAttendees.Split(';');
					foreach(string r in attendees){
						EventAttendee attendee = new EventAttendee();
						attendee.Email=GenerateDummyEmail(r);
						attendee.DisplayName = r;
						attendee.Optional= false;
						e.Attendees.Add(attendee);
					}
				}
				
				
				if(this.OptionalAttendees!=null) {
					string[] attendees = this.OptionalAttendees.Split(';');
					foreach(string r in attendees){
						EventAttendee attendee = new EventAttendee();
						attendee.Email=GenerateDummyEmail(r);
						attendee.DisplayName = r;
						attendee.Optional= true;
						e.Attendees.Add(attendee);
					}
				}
				
				
			}
			
			
			return e;			
		}
		
		private DateTime CastEventDateTimeToDateTime(Google.Apis.Calendar.v3.Data.EventDateTime edt)
		{
			DateTime dt;
			
			if (edt.Date != null) {
				dt = DateTime.Parse(edt.Date);
			} else {
				dt = (DateTime)edt.DateTime;
			}
			
			return dt;
		}
		
		private string GenerateDummyEmail(string name){
			string dummyEmail = "dummy@dummy.com";
			if(name!=null){
				dummyEmail = emailPattern.Replace(name,"")+"@d.com";
				log.DebugFormat("Dummy Email Created: {0}",dummyEmail);
			}
			return dummyEmail;
		}
		
		#region Overload Operators		
		public static explicit operator Google.Apis.Calendar.v3.Data.Event(Appointment a) 
		{
			return a.ToGoogleCalendarEvent();
		}
		
		#endregion		
		
		#region Equals and GetHashCode implementation
		public override bool Equals(object obj)
		{
			Appointment other = obj as Appointment;
			if (other == null)
				return false;
			return this.Start == other.Start 
				&& this.End == other.End 
				&& this.Subject == other.Subject 
				&& this.Location == other.Location 
				&& this.AllDayEvent == other.AllDayEvent;
		}

		public override int GetHashCode()
		{
			int hashCode = 0;
			unchecked {
				hashCode += 1000000007 * Start.GetHashCode();
				hashCode += 1000000009 * End.GetHashCode();
				if (Subject != null)
					hashCode += 1000000021 * Subject.GetHashCode();
				if (Body != null)
					hashCode += 1000000033 * Body.GetHashCode();
				if (Location != null)
					hashCode += 1000000087 * Location.GetHashCode();
				if (GoogleId != null)
					hashCode += 1000000093 * GoogleId.GetHashCode();
				if (OfficeId != null)
					hashCode += 1000000097 * OfficeId.GetHashCode();
				hashCode += 1000000103 * AllDayEvent.GetHashCode();
			}
			return hashCode;
		}

		public static bool operator ==(Appointment lhs, Appointment rhs)
		{
			if (ReferenceEquals(lhs, rhs))
				return true;
			if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null))
				return false;
			return lhs.Equals(rhs);
		}

		public static bool operator !=(Appointment lhs, Appointment rhs)
		{
			return !(lhs == rhs);
		}

		#endregion
		
		public override string ToString()
		{
			return Start + " to " + End + " " + Subject + "[" + Location + "]  OID=" + OfficeId + " GID=" + GoogleId;
		}
		
		
		
	}
}
